package ge.modules.ia;

import ge.engine.Engine;
import ge.engine.Rule;
import ge.modules.Module;

import java.util.Comparator;
import java.util.PriorityQueue;


/**
 *  This class has the labor of manage and dispatch all the messages between state machines.
 * @author abel.botrdonado
 *
 */
public class MessageDispatch implements Module, Rule
{
	private PriorityQueue<Message> delayedMessages;
	private static MessageDispatch instance = null;
	public int currentTime ;
	
	public static MessageDispatch get()
	{
		if(instance == null)
		{
			instance =  new MessageDispatch();
		}
		
		return instance;
	}
	
	
	private MessageDispatch()
	{
		delayedMessages = new PriorityQueue<Message>();
		Comparator<Message>  c = new Comparator<Message>() {
			
			@Override
			public int compare(Message o1, Message o2) {
				return o1.delay.compareTo(o2.delay);
			}
		};
		
		delayedMessages = new PriorityQueue<Message>(10,c);
		currentTime = 0;
	}
	/**
	 * 	Create and sends a Message.
	 * @param delay If delay is equal or less than 0 the message will be send immediately.
	 * 	If not, it will be sent in that time
	 * @param sender
	 * @param reciverId
	 * @param messageType
	 * @param extraInfo
	 */
	public void sendMessage(int delay, StateMachineModule<?> sender, int reciverId, int messageType, Object extraInfo)
	{
		
		Message m = new Message(sender,
				StateMachineBaseEntity.get().getEntity(reciverId),
				messageType,
				delay,
				extraInfo);
		
		if(m.reciver == null)
			return;
		
		if(delay <= 0)
		{
			this.dispatchMessage(m);
			return;
		}
		
		
		m.delay += this.currentTime;
		delayedMessages.add(m);
	}
	/**
	 * 	Actually sends the message
	 * @param m
	 */
	private void dispatchMessage(Message m)
	{
		if(m != null)
			m.reciver.handleMessage(m);
	}
	/**
	 * Try to send the delayed messages
	 */
	private void dispatchDelayedMessages()
	{
		
		while( !delayedMessages.isEmpty() && delayedMessages.peek().delay <  currentTime)
		{
			dispatchMessage(delayedMessages.poll());
		}
	}
	
	@Override
	public void update() 
	{
	  currentTime += Engine.updateTick;
	  if(!delayedMessages.isEmpty())
		  dispatchDelayedMessages();
		  
	}

	/**
	 * Nothing
	 */
	@Override
	public void draw() {
	}


	@Override
	public void delete() 
	{
		delayedMessages.clear();
	}
}
